package pe.com.ztaxi.taxis.util;

import java.util.ArrayList;
import java.util.List;

import org.springframework.stereotype.Component;

import pe.com.ztaxi.taxis.model.Punto;

/**
 * 
 * Methods to encode and decode a polyline with Google polyline
 * encoding/decoding scheme. See
 * https://developers.google.com/maps/documentation/utilities/polylinealgorithm
 */

@Component
public class PolylineEncoder {

	 private static StringBuffer encodeSignedNumber(int num) {
	 int sgn_num = num << 1;
	 if (num < 0) {
	 sgn_num = ~(sgn_num);
	 }
	 return (encodeNumber(sgn_num));
	 }
	
	 private static StringBuffer encodeNumber(int num) {
	 StringBuffer encodeString = new StringBuffer();
	 while (num >= 0x20) {
	 int nextValue = (0x20 | (num & 0x1f)) + 63;
	 encodeString.append((char) (nextValue));
	 num >>= 5;
	 }
	 num += 63;
	 encodeString.append((char) (num));
	 return encodeString;
	 }

	/**
	 * 
	 * Encode a polyline with Google polyline encoding method
	 * 
	 * @param list
	 *            the polyline
	 * @param precision
	 *            1 for a 6 digits encoding, 10 for a 5 digits encoding.
	 * @return the encoded polyline, as a String
	 */
	 public static String encode(List<Punto> list) {
	 StringBuffer encodedPoints = new StringBuffer();
	 int prev_lat = 0, prev_lng = 0;
	 for (Punto trackpoint : list) {
	 int lat = (int) (trackpoint.getLatitud() * 1E5);
	 int lng = (int) (trackpoint.getLongitud() * 1E5);
	 encodedPoints.append(encodeSignedNumber(lat - prev_lat));
	 encodedPoints.append(encodeSignedNumber(lng - prev_lng));
	 prev_lat = lat;
	 prev_lng = lng;
	 }
	 return encodedPoints.toString();
	 }

	/** 
	 * Decode un "Google-encoded" polyline
	 * @param encodedString	
	 * @return the polyline.
	 */
	public static ArrayList<Punto> decodePoly(String encoded) {
		ArrayList<Punto> poly = new ArrayList<Punto>();
		int index = 0, len = encoded.length();
		int lat = 0, lng = 0;
		while (index < len) {
			int b, shift = 0, result = 0;
			do {
				b = encoded.charAt(index++) - 63;
				result |= (b & 0x1f) << shift;
				shift += 5;
			} while (b >= 0x20);
			int dlat = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));
			lat += dlat;
			shift = 0;
			result = 0;
			do {
				b = encoded.charAt(index++) - 63;
				result |= (b & 0x1f) << shift;
				shift += 5;
			} while (b >= 0x20);
			int dlng = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));
			lng += dlng;
			Punto p = new Punto();
			p.setLatitud(((double) lat / 1E5));
			p.setLongitud(((double) lng / 1E5));
			poly.add(p);
		}
		return poly;
	}

}
